"""
数据模型定义模块
包含系统中所有数据库表的模型定义，包括用户、学院、班级、课程和成绩等信息
"""

from datetime import datetime
from .database import db, login_manager
from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hash

@login_manager.user_loader
def load_user(user_id):
    """
    用户加载回调函数，用于Flask-Login
    
    根据用户ID加载对应的用户对象。用户ID的格式为"用户类型_ID"，
    例如："teacher_123"或"student_456"
    
    Args:
        user_id (str): 用户ID，格式为"用户类型_ID"
        
    Returns:
        Teacher/Student: 根据用户类型返回对应的用户对象
    """
    # 从user_id中解析用户类型和ID
    user_type, user_id = user_id.split('_')
    if user_type == 'teacher':
        return Teacher.query.get(int(user_id))
    else:
        return Student.query.get(int(user_id))

class Registration(db.Model):
    """
    用户注册信息表
    
    存储用户注册时的基本信息，包括教师和学生的注册申请。
    
    字段说明：
        registration_id: 注册记录的唯一标识
        user_type: 用户类型（'teacher'或'student'）
        user_id: 工号/学号
        username: 用户名（唯一）
        email: 电子邮箱
        phone: 手机号码
        avatar: 头像图片路径
        password: 加密存储的密码
        status: 注册状态（'pending'待审核, 'approved'已通过, 'rejected'已拒绝）
        created_at: 注册申请创建时间
        updated_at: 记录最后更新时间
    """
    __tablename__ = 'registrations'
    
    registration_id = db.Column(db.Integer, primary_key=True)
    user_type = db.Column(db.String(10), nullable=False)
    user_id = db.Column(db.String(20), nullable=False)
    username = db.Column(db.String(50), unique=True, nullable=False)
    email = db.Column(db.String(120), nullable=False)
    phone = db.Column(db.String(20), nullable=False)
    avatar = db.Column(db.String(255))
    password = db.Column(db.String(200), nullable=False)
    status = db.Column(db.String(20), default='approved')
    created_at = db.Column(db.DateTime, server_default=db.func.now())
    updated_at = db.Column(db.DateTime, server_default=db.func.now(), onupdate=db.func.now())

    def set_password(self, password):
        """
        设置用户密码
        
        使用werkzeug.security提供的函数对密码进行加密存储
        
        Args:
            password (str): 原始密码
        """
        self.password = generate_password_hash(password)

    def check_password(self, password):
        """
        验证用户密码
        
        将输入的密码与数据库中存储的加密密码进行比对
        
        Args:
            password (str): 待验证的密码
            
        Returns:
            bool: 密码是否正确
        """
        return check_password_hash(self.password, password)

class College(db.Model):
    """
    学院信息表
    
    存储学校各个学院的基本信息
    
    字段说明：
        college_id: 学院唯一标识
        college_name: 学院名称
    """
    __tablename__ = 'colleges'

    college_id = db.Column(db.Integer, primary_key=True)
    college_name = db.Column(db.String(50), nullable=False)

class Teacher(db.Model, UserMixin):
    """
    教师信息表
    
    存储教师的基本信息，继承UserMixin以支持Flask-Login的用户认证功能
    
    字段说明：
        teacher_id: 教师唯一标识
        name: 教师姓名
        college_id: 所属学院ID（外键关联colleges表）
        created_at: 记录创建时间
        updated_at: 记录最后更新时间
        
    关系：
        college: 与College表的一对多关系，一个学院可以有多个教师
    """
    __tablename__ = 'teachers'
    
    teacher_id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50), nullable=False)
    college_id = db.Column(db.Integer, db.ForeignKey('colleges.college_id'))
    created_at = db.Column(db.DateTime, server_default=db.func.now())
    updated_at = db.Column(db.DateTime, server_default=db.func.now(), onupdate=db.func.now())
    # 在 College 模型中会自动添加一个 teachers 属性
    college = db.relationship('College', backref=db.backref('teachers', lazy=True))
    
    def get_id(self):
        """
        获取用户唯一标识符
        
        重写UserMixin的方法，返回格式为"teacher_ID"的字符串
        
        Returns:
            str: 格式化的用户ID
        """
        return f'teacher_{self.teacher_id}'

class Class(db.Model):
    """
    班级信息表
    
    存储班级的基本信息，包括班级名称和所属学院
    
    字段说明：
        class_id: 班级唯一标识（自增）
        class_name: 班级名称（唯一）
        college_id: 所属学院ID（外键关联colleges表）
        created_at: 记录创建时间
        updated_at: 记录最后更新时间
        
    关系：
        college: 与College表的多对一关系，一个学院可以有多个班级
        students: 与Student表的一对多关系，一个班级可以有多个学生
    """
    __tablename__ = 'classes'
    
    class_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    class_name = db.Column(db.String(50), nullable=False, unique=True)
    college_id = db.Column(db.Integer, db.ForeignKey('colleges.college_id'), nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
    
    college = db.relationship('College', backref='classes', lazy=True)
    students = db.relationship('Student', backref='class', lazy=True)
    
    def to_dict(self):
        """
        将班级信息转换为字典格式
        
        用于API返回或JSON序列化
        
        Returns:
            dict: 包含班级基本信息的字典
        """
        return {
            'class_id': self.class_id,
            'class_name': self.class_name,
            'college_id': self.college_id
        }

class Student(db.Model, UserMixin):
    """
    学生信息表
    
    存储学生的基本信息，继承UserMixin以支持Flask-Login的用户认证功能
    
    字段说明：
        student_id: 学生唯一标识
        name: 学生姓名
        student_number: 学号（唯一）
        gender: 性别
        class_id: 所属班级ID（外键关联classes表）
        
    关系：
        class: 与Class表的多对一关系，一个班级可以有多个学生
    """
    __tablename__ = 'students'
    student_id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50), nullable=False)
    student_number = db.Column(db.String(20), unique=True, nullable=False)
    gender = db.Column(db.String(10), nullable=False)
    class_id = db.Column(db.Integer, db.ForeignKey('classes.class_id'), nullable=False)
    
    def get_id(self):
        """
        获取用户唯一标识符
        
        重写UserMixin的方法，返回格式为"student_ID"的字符串
        
        Returns:
            str: 格式化的用户ID
        """
        return f'student_{self.student_id}'
        
    def to_dict(self):
        """
        将学生信息转换为字典格式
        
        用于API返回或JSON序列化
        
        Returns:
            dict: 包含学生基本信息的字典
        """
        return {
            'student_id': self.student_id,
            'name': self.name,
            'student_number': self.student_number,
            'gender': self.gender,
            'class_id': self.class_id
        }

class Course(db.Model):
    """
    课程信息表
    
    存储课程的基本信息，包括课程名称、学分、开课学期等
    
    字段说明：
        course_id: 课程唯一标识
        course_name: 课程名称
        credits: 学分
        semester: 开课学期
        college_id: 开课学院ID（外键关联colleges表）
        
    关系：
        college: 与College表的多对一关系，一个学院可以开设多门课程
    """
    __tablename__ = 'courses'
    course_id = db.Column(db.Integer, primary_key=True)
    course_name = db.Column(db.String(100), nullable=False)
    credits = db.Column(db.Float, nullable=False)
    semester = db.Column(db.String(20), nullable=False)
    college_id = db.Column(db.Integer, db.ForeignKey('colleges.college_id'))
    college = db.relationship('College', backref='courses')

class Grade(db.Model):
    """
    成绩信息表
    
    存储学生的课程成绩信息，包括平时成绩、期末成绩和总评成绩
    
    字段说明：
        grade_id: 成绩记录唯一标识
        student_number: 学号（外键关联students表）
        course_id: 课程ID（外键关联courses表）
        teacher_id: 教师ID（外键关联teachers表）
        semester: 学期
        regular_score: 平时成绩
        final_score: 期末成绩
        total_score: 总评成绩（平时60%+期末40%）
        
    关系：
        course: 与Course表的多对一关系，一门课程可以有多个成绩记录
        student: 与Student表的多对一关系，一个学生可以有多个成绩记录
    """
    __tablename__ = 'grades'
    grade_id = db.Column(db.Integer, primary_key=True)
    student_number = db.Column(db.String(20), db.ForeignKey('students.student_number'), nullable=False)
    course_id = db.Column(db.Integer, db.ForeignKey('courses.course_id'), nullable=False)
    teacher_id = db.Column(db.Integer, db.ForeignKey('teachers.teacher_id'), nullable=False)
    semester = db.Column(db.String(20), nullable=False)
    regular_score = db.Column(db.Float, nullable=False)
    final_score = db.Column(db.Float, nullable=False)
    total_score = db.Column(db.Float, nullable=False, 
                          server_default=db.text('regular_score * 0.6 + final_score * 0.4'))
    
    course = db.relationship('Course', backref=db.backref('grades', lazy=True))
    student = db.relationship('Student', backref=db.backref('grades', lazy=True))
    
    def calculate_total_score(self):
        """
        计算总评成绩
        
        根据平时成绩（60%）和期末成绩（40%）计算总评成绩
        
        Returns:
            float: 计算得到的总评成绩，如果成绩数据不完整则返回None
        """
        if self.regular_score is not None and self.final_score is not None:
            return self.regular_score * 0.6 + self.final_score * 0.4
        return None
        
    def to_dict(self):
        """
        将成绩信息转换为字典格式
        
        用于API返回或JSON序列化
        
        Returns:
            dict: 包含成绩信息的字典
        """
        return {
            'grade_id': self.grade_id,
            'student_number': self.student_number,
            'course_id': self.course_id,
            'teacher_id': self.teacher_id,
            'semester': self.semester,
            'regular_score': self.regular_score,
            'final_score': self.final_score,
            'total_score': self.total_score
        } 